package com.dingreading.cloud.soms.controller;

import com.alibaba.fastjson.JSONArray;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.dto.LoginDataDto;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.soms.dto.MemberBorrowDto;
import com.dingreading.cloud.soms.entity.BorrowBook;
import com.dingreading.cloud.soms.entity.BorrowBookLog;
import com.dingreading.cloud.soms.entity.StoreBooks;
import com.dingreading.cloud.soms.service.*;
import com.dingreading.cloud.soms.util.LoginInfoUtil;
import com.dingreading.cloud.soms.util.redis.RedisService;
import com.google.common.collect.Lists;
import com.mybatisflex.core.paginate.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/front/borrowBook")
@Api(tags = "门店-借书记录管理")
public class FrontBorrowBookController {

    @Resource
    private BorrowBookService borrowBookService;
    @Resource
    private BorrowBookLogService borrowBookLogService;
    @Resource
    private StoreBooksService storeBooksService;
    @Resource
    private MembersService membersService;
    @Resource
    private MemberCashService memberCashService;
    @Resource
    private StoresService storesService;
    @Resource
    private RedisService redisService;

    @ApiOperation(value = "分页列表")
    @PostMapping(value = "/pageList")
    public R<Object> pageList(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "分页公共类") PageUtil pageUtil,
            @ApiParam(value = "书名/借书人姓名/借书人电话") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "借阅状态 1.借阅中 2.已还书") @RequestParam(value = "returnStatus", required = false) Integer returnStatus,
            @ApiParam(value = "借书开始时间 yyyy-MM-dd") @RequestParam(value = "beginTime", required = false) String beginTime,
            @ApiParam(value = "借书结束时间 yyyy-MM-dd") @RequestParam(value = "endTime", required = false) String endTime,
            @ApiParam(value = "查询未还借阅 1.2天内快到期 2.已过期") @RequestParam(value = "searchType", required = false) Integer searchType
    ) {
        Page<BorrowBook> results = borrowBookService.pageList(pageUtil, storeUid, keyword, returnStatus, beginTime, endTime, searchType);

        List<BorrowBook> list = results.getRecords();
        if (CollectionUtils.isNotEmpty(list)) {
            List<Long> borrowIds = list.stream().map(BorrowBook::getId).collect(Collectors.toList());
            List<BorrowBookLog> logList = borrowBookLogService.getByStoreUidAndBorrowIds(storeUid, borrowIds);
            Map<Long, List<BorrowBookLog>> map = new HashMap<>();
            if (CollectionUtils.isNotEmpty(logList)) {
                map = logList.stream().collect(Collectors.groupingBy(BorrowBookLog::getBorrowBookId));
            }

            for (BorrowBook borrowBook : list) {
                borrowBook.setList(map.get(borrowBook.getId()));
            }
        }

        PageBeanDto dto = new PageBeanDto();
        dto.setTotal(results.getTotalRow());
        dto.setList(list);

        return R.ok(dto);
    }

    @ApiOperation(value = "判断会员是否有已借未还的记录")
    @PostMapping(value = "/judgeHaveBorrow")
    public R<Object> judgeHaveBorrow(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "借阅人uid") @RequestParam(value = "memberUid") String memberUid
    ) {
        long cnt = borrowBookService.getBorrowingCnt(storeUid, memberUid);
        return R.ok(cnt);
    }

    @ApiOperation(value = "新建/修改借书记录")
    @PostMapping(value = "/newLog")
    public R<Object> newLog(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "id") @RequestParam(value = "id", required = false) Long id,
            @ApiParam(value = "借阅人姓名") @RequestParam(value = "name") String name,
            @ApiParam(value = "借阅人电话") @RequestParam(value = "mob") String mob,
            @ApiParam(value = "借阅人uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "预计借阅天数") @RequestParam(value = "bookDay") Integer bookDay,
            @ApiParam(value = "预计还书时间") @RequestParam(value = "bookTime") String bookTime,
            @ApiParam(value = "书籍json [{id:0,name:null,storeBookId:0,price:0，press:''}]") @RequestParam(value = "books") String books,
            @ApiParam(value = "备注") @RequestParam(value = "remark", required = false) String remark
    ) throws Exception {
        if (StringUtils.isBlank(name)) return R.fail("借阅人姓名不能为空");
        if (StringUtils.isBlank(mob)) return R.fail("借阅人电话不能为空");
        if (StringUtils.isBlank(memberUid)) return R.fail("借阅人uid不能为空");
        if (bookDay == null || bookDay <= 0) return R.fail("预计借阅天数不能为空");
        if (StringUtils.isBlank(bookTime)) return R.fail("预计还书时间不能为空");

        if (StringUtils.isBlank(books)) return R.fail("书籍数据不能为空");
        List<BorrowBookLog> bookLogs = JSONArray.parseArray(books, BorrowBookLog.class);
        if (CollectionUtils.isEmpty(bookLogs)) return R.fail("书籍数据解析错误");

        // 判断书籍是否可以借阅
        R<Map<Long, StoreBooks>> r = judgeBookBorrow(storeUid, id, bookLogs);
        if (R.isError(r))
            return R.fail(r.getMsg());

        Map<Long, StoreBooks> storeBooksMap = r.getData();
        if (id == null || id <= 0) {
            // 新增
            BorrowBook borrowBook = new BorrowBook();
            borrowBook.setName(name);
            borrowBook.setMob(mob);
            borrowBook.setMemberUid(memberUid);
            borrowBook.setCorpUid(corpUid);
            borrowBook.setStoreUid(storeUid);
            borrowBook.setStoreName(storeName);
            borrowBook.setAddStaffUid(staffUid);
            borrowBook.setAddStaffName(staffName);
            borrowBook.setEditStaffUid(staffUid);
            borrowBook.setEditStaffName(staffName);
            borrowBook.setStatus(1);
            borrowBook.setBorrowNum(bookLogs.size());
            borrowBook.setReturnNum(0);
            borrowBook.setBookDay(bookDay);
            borrowBook.setBookTime(bookTime);
            borrowBook.setRemark(remark);
            borrowBookService.saveOrUpdate(borrowBook);

            if (borrowBook.getId() == null || borrowBook.getId() <= 0)
                return R.fail("保存失败");
            // 新增借阅记录书籍信息
            newLog(borrowBook.getId(), corpUid, storeUid, memberUid, bookLogs, storeBooksMap);
        } else {
            // 修改
            BorrowBook borrowBook = borrowBookService.getById(id);
            if (borrowBook == null) return R.fail("获取失败");
            if (borrowBook.getStatus().equals(2)) return R.fail("已还书不能修改");
            if (borrowBook.getReturnNum() > 0) return R.fail("还书中不能修改");

            borrowBook.setName(name);
            borrowBook.setMob(mob);
            borrowBook.setEditStaffUid(staffUid);
            borrowBook.setEditStaffName(staffName);
            borrowBook.setBorrowNum(bookLogs.size());
            borrowBook.setBookDay(bookDay);
            borrowBook.setBookTime(bookTime);
            borrowBook.setRemark(remark);
            borrowBookService.saveOrUpdate(borrowBook);

            List<BorrowBookLog> borrowBookLogs = borrowBookLogService.getByBorrowBookId(storeUid, id);
            if (CollectionUtils.isEmpty(borrowBookLogs)) {
                // 新增借阅记录书籍信息
                newLog(id, corpUid, storeUid, memberUid, bookLogs, storeBooksMap);
            } else {
                // 修改或新增记录
                List<Long> logIds = bookLogs.stream().map(BorrowBookLog::getId).filter(Objects::nonNull).collect(Collectors.toList());

                Map<Long, StoreBooks> map = new HashMap<>();
                List<Long> editStoreBookIds = bookLogs.stream()
                        .filter(borrowBookLog -> (borrowBookLog.getId() == null || borrowBookLog.getId() <= 0) && borrowBookLog.getStoreBookId() != null)
                        .map(BorrowBookLog::getStoreBookId).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(editStoreBookIds)) {
                    List<StoreBooks> editStoreBooksList = storeBooksService.listByIds(editStoreBookIds);
                    if (CollectionUtils.isNotEmpty(editStoreBooksList)) {
                        map = editStoreBooksList.stream().collect(Collectors.toMap(StoreBooks::getId, Function.identity()));
                    }
                }

                List<BorrowBookLog> newList = new ArrayList<>();
                for (BorrowBookLog data : bookLogs) {
                    if (data.getId() == null || data.getId() <= 0) {
                        // 添加新记录
                        data.setBorrowBookId(id);
                        data.setCorpUid(corpUid);
                        data.setStoreUid(storeUid);
                        data.setMemberUid(memberUid);
                        data.setStatus(1);
                        if (data.getStoreBookId() != null) {
                            StoreBooks storeBooks = map.get(data.getStoreBookId());
                            if (storeBooks != null) {
                                data.setBookId(storeBooks.getBooksId());
                                data.setImg(storeBooks.getImg());
                                data.setIsbn(storeBooks.getIsbn());
                            }
                        }
                        newList.add(data);
                    } else {
                        // 更新记录
                        newList.add(data);
                    }
                }
                // 删除不要的数据
                borrowBookLogService.deleteByBorrowBookIdAndIdsNot(storeUid, id, logIds);
                // 新增或更新数据
                borrowBookLogService.saveOrUpdateBatch(newList);
            }
        }

        // 清空门店缓存
        redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);
        return R.ok();
    }

    @ApiOperation(value = "获取借书详情")
    @PostMapping(value = "/getBean")
    public R<Object> getBean(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "id") @RequestParam(value = "id") Long id
    ) {
        BorrowBook log = borrowBookService.getById(id);
        if (log == null) return R.fail("获取失败");

        List<BorrowBookLog> list = borrowBookLogService.getByBorrowBookId(storeUid, id);
        log.setList(list);

        return R.ok(log);
    }

    @ApiOperation(value = "保存还书备注")
    @PostMapping(value = "/saveRemark")
    public R<Object> saveRemark(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "id") @RequestParam(value = "id") Long id,
            @ApiParam(value = "还书备注") @RequestParam(value = "remark") String remark
    ) {
        BorrowBook borrowBook = borrowBookService.getByStoreUidAndId(storeUid, id);
        if (borrowBook == null) return R.fail("获取失败");

        if (borrowBook.getStatus().equals(2)) {
            long l = System.currentTimeMillis();
            long time = borrowBook.getReturnTime().getTime();
            long l1 = l - time;
            // 10天
            long tenDay = 10 * 24 * 60 * 60 * 1000;
            if (l1 > tenDay)
                return R.fail("完成还书超过10天，不能操作");
        }

        borrowBookService.saveRemark(storeUid, id, remark);
        return R.ok();
    }

    @ApiOperation(value = "借阅还书")
    @PostMapping(value = "/returnBook")
    public R<Object> returnBook(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "借阅id") @RequestParam(value = "id") Long id,
            @ApiParam(value = "借阅书籍id") @RequestParam(value = "logId") Long logId
    ) {
        BorrowBook borrowBook = borrowBookService.getByStoreUidAndId(storeUid, id);
        if (borrowBook == null) return R.fail("获取失败");
        if (borrowBook.getStatus().equals(2)) return R.fail("还书已完成，不能重复还书");

        BorrowBookLog bookLog = borrowBookLogService.getById(logId);
        if (bookLog.getStatus().equals(2)) return R.fail("这本书已经还过了");

        Date date = DateUtil.getNowDatetime();
        // 更新借阅记录的归还信息
        long l = borrowBookLogService.updateReturnStatus(storeUid, id, logId, staffUid, staffName, date);
        if (l <= 0) return R.fail("还书失败");
        l = borrowBookService.setReturn(storeUid, id, borrowBook.getReturnNum(), borrowBook.getBorrowNum(), date);
        if (l <= 0) return R.fail("更新借阅信息失败");

        // 清空门店缓存
        redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);
        return R.ok();
    }

    @ApiOperation(value = "按姓名和手机号获取会员")
    @PostMapping(value = "/getByNameAndPhone")
    public R<Object> getByNameAndPhone(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工姓名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "姓名或手机号") @RequestParam(value = "keyword") String keyword
    ) {
        // 获取员工信息
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();
        Integer operationType = loginDto.getCurrentOperationType();

        if (StringUtils.isBlank(keyword))
            return R.fail("请填写姓名或手机号");

        List<MemberBorrowDto> list = new ArrayList<>();
        if (operationType.equals(EnumOperationType.SELF.getType()) || operationType.equals(EnumOperationType.CONSORTIUM.getType())) {
            if (StringUtil.isChinese(keyword)) {
                if (keyword.length() < 2)
                    return R.fail("名字至少填写2位");
            } else {
                if (StringUtils.isNumeric(keyword)) {
                    if (keyword.length() != 11)
                        return R.fail("请填写完整的手机号");
                }
            }
            // 自营或联营店，可跨店查询会员
            List<String> storeUidList = storesService.listBySelfAndConsortium();
            if (CollectionUtils.isEmpty(storeUidList))
                return R.fail(0, "未查询到自营或联营门店");

            list = membersService.borrowMemberList(storeUidList, keyword);
            if (CollectionUtils.isEmpty(list))
                return R.fail(0, "未查询到会员");
        } else {
            if (StringUtil.isChinese(keyword)) {
                if (keyword.length() < 2)
                    return R.fail("名字至少填写2位");
            } else {
                if (StringUtils.isNumeric(keyword)) {
                    if (keyword.length() < 4)
                        return R.fail("手机号至少填写4位");
                }
            }
            list = membersService.borrowMemberList(corpUid, storeUid, keyword);
            if (CollectionUtils.isEmpty(list))
                return R.fail(0, "未查询到会员");
        }

        List<String> memberUidList = list.stream().map(MemberBorrowDto::getUid).collect(Collectors.toList());

        // 设置交押金状态
        Map<String, Integer> map = memberCashService.lastByMemberUid(memberUidList);
        for (MemberBorrowDto dto : list) {
            Integer type = map.get(dto.getUid());
            dto.setType(type != null ? type : 2);
        }

        return R.ok(list);
    }

    /**
     * 新增借阅记录书籍信息
     */
    private void newLog(Long id, String corpUid, String storeUid, String memberUid, List<BorrowBookLog> bookLogs, Map<Long, StoreBooks> storeBooksMap) {
        for (BorrowBookLog bookLog : bookLogs) {
            bookLog.setCorpUid(corpUid);
            bookLog.setStoreUid(storeUid);
            bookLog.setMemberUid(memberUid);
            bookLog.setBorrowBookId(id);
            bookLog.setStatus(1);
            if (bookLog.getStoreBookId() != null) {
                StoreBooks storeBooks = storeBooksMap.get(bookLog.getStoreBookId());
                if (storeBooks != null) {
                    bookLog.setBookId(storeBooks.getBooksId());
                    bookLog.setImg(storeBooks.getImg());
                    bookLog.setIsbn(storeBooks.getIsbn());
                }
            }
        }
        borrowBookLogService.saveOrUpdateBatch(bookLogs);
    }

    /**
     * 判断书籍是否可以借阅
     */
    private R<Map<Long, StoreBooks>> judgeBookBorrow(String storeUid, Long borrowBookId, List<BorrowBookLog> bookLogs) {
        

        List<Long> storeBookIds = new ArrayList<>();
        List<Long> logIds = new ArrayList<>();
        for (BorrowBookLog bookLog : bookLogs) {
            if (bookLog.getStoreBookId() != null && bookLog.getStoreBookId() > 0)
                storeBookIds.add(bookLog.getStoreBookId());
            if (bookLog.getId() != null && bookLog.getId() > 0)
                logIds.add(bookLog.getId());
        }

        // 查询借阅单要删除书单的数量
        Map<Long, Long> deletedBorrowBookCntMap = new HashMap<>();
        if (borrowBookId != null && borrowBookId > 0) {
            deletedBorrowBookCntMap = borrowBookLogService.deleteBorrowBookCnt(storeUid, borrowBookId, logIds);
        }

        Map<Long, StoreBooks> storeBooksMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(storeBookIds)) {
            List<StoreBooks> storeBooksList = storeBooksService.listByIds(storeBookIds);
            if (CollectionUtils.isEmpty(storeBooksList))
                return R.fail("门店书籍获取失败");

            storeBooksMap = storeBooksList.stream().collect(Collectors.toMap(StoreBooks::getId, Function.identity()));

            Map<Long, List<BorrowBookLog>> borrowMap = bookLogs.stream()
                    .filter(log -> log.getStoreBookId() != null && log.getId() == null)
                    .collect(Collectors.groupingBy(BorrowBookLog::getStoreBookId));
            Map<Long, Long> borrowedCntMap = borrowBookLogService.getByStoreBookIdBorrowCnt(storeUid, Lists.newArrayList(borrowMap.keySet()));

            for (Map.Entry<Long, List<BorrowBookLog>> entry : borrowMap.entrySet()) {
                Long storeBookId = entry.getKey();
                List<BorrowBookLog> value = entry.getValue();
                StoreBooks storeBooks = storeBooksMap.get(storeBookId);
                Integer borrowCount = NepUtil.nullToZero(storeBooks.getBorrowCount());

                long borrowedCnt = NepUtil.nullToZero(borrowedCntMap.get(storeBookId));
                long delBorrowedCnt = !deletedBorrowBookCntMap.isEmpty() ? NepUtil.nullToZero(deletedBorrowBookCntMap.get(storeBookId)) : 0;
                long l = borrowedCnt + value.size() - delBorrowedCnt;
                if (l > borrowCount) {
                    String builder = storeBooks.getBookName().concat(" 的可借数量不足") +
                            "，库存数量：" + NepUtil.nullToZero(storeBooks.getStockCount()) +
                            "，可借数量：" + borrowCount +
                            "，剩余可借数量：" + (borrowCount - borrowedCnt) +
                            "，已借数量：" + borrowedCnt;
                    return R.fail(builder);
                }
            }
        }
        return R.ok(storeBooksMap);
    }

}